#pragma once

#include "config.h"
#include "opcode.h"

class Gateway;
class ServiceManager;

#define CREATE_SERVICE(s)		inline Service* Create##s(void)	\
								{								\
									Service* p = SAFE_NEW s();	\
									p->SetType(#s);				\
									return p;					\
								}

class Service : public Register
{
	friend class ServiceManager;

public:

	Service();
	virtual ~Service();

	virtual void Initialize(ServiceManager* manager, const vector<string>& params, NetPacket* packet = NULL);

	virtual void Update() = 0;

	string GetStringParam(uint16 index);
	int GetIntParam(uint16 index);

	inline bool IsDone()				{ return m_bDone; };
	inline Gateway* GetGateway()		{ return m_gateway; }
	inline ServiceManager* GetManager() { return m_serviceManager; }
	inline uint16 GetParamsSize() const { return m_params.size(); }

	inline string GetType() const		{ return m_type; };
	inline void SetType(const string& type){ m_type = type; };

	inline uint16 GetRef() const { return m_ref; }

protected:

	Gateway*		m_gateway;
	ServiceManager*	m_serviceManager;

	NetPacket*			m_packet;
	string			m_type;
		
	vector<string>	m_params;

	bool			m_bDone;
	uint16			m_handle;
	uint16			m_ref;
};

typedef Service* (*RegService)(void);
typedef	map<string, RegService>	CreatorMap;

#define REG_SERVICE(s)	{ ServiceFactory::m_creatorMap[#s] = Create##s; }

class ServiceFactory
{
public:
	
	ServiceFactory(){}
	~ServiceFactory(){}

	Service* Create(const string& name);

	static CreatorMap	m_creatorMap;
};

typedef uint32							ServiceHandle;
typedef	vector<Service*>				ServiceList;
typedef	queue<Service*>					ServiceQueue;
typedef	map<ServiceHandle, Service*>	ServiceMap;

class ServiceManager
{
public:

	ServiceManager(Gateway* gateway);
	virtual ~ServiceManager();

	void Update();

	ServiceHandle	CallService(const string& name, const vector<string>& params, NetPacket* packet = NULL);
	Service*		FindService(ServiceHandle handle);

	Service*		AddRef(ServiceHandle handle);
	void			ReleaseRef(ServiceHandle handle);

	inline bool				Empty()				{return m_workList.empty() && m_appendQueue.empty();};
	inline ServiceFactory*	GetServiceFactory()	{return m_serviceFactory;};
	inline Gateway*	    GetGateway()		{return m_gateway;}

private:

	Gateway*	    m_gateway;
	ServiceFactory*	m_serviceFactory;

	ServiceList		m_workList;	
	ServiceQueue	m_appendQueue;
	ServiceQueue	m_removeQueue;
	ServiceMap		m_srvMap;

	uint32			m_counter;
};